package com.yomahub.liteflow.core;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.annotation.AnnoUtil;
import com.yomahub.liteflow.annotation.LiteflowRetry;
import com.yomahub.liteflow.common.ChainConstant;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.flow.executor.NodeExecutor;
import com.yomahub.liteflow.monitor.MonitorBus;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
import com.yomahub.liteflow.spi.holder.ContextAwareHolder;
import com.yomahub.liteflow.spi.holder.LiteflowComponentSupportHolder;

/**
 * 组件初始化器
 *
 * @author Bryan.Zhang
 * @since 2.6.0
 */
public class ComponentInitializer {

	private static ComponentInitializer instance;

	public static ComponentInitializer loadInstance() {
		if (ObjectUtil.isNull(instance)) {
			instance = new ComponentInitializer();
		}
		return instance;
	}

	public NodeComponent initComponent(NodeComponent nodeComponent, NodeTypeEnum type, String name, String nodeId) {
		nodeComponent.setNodeId(nodeId);
		nodeComponent.setSelf(nodeComponent);
		nodeComponent.setType(type);

		// 设置MonitorBus，如果没有就不注入
		if (ContextAwareHolder.loadContextAware().hasBean(ChainConstant.MONITOR_BUS)) {
			MonitorBus monitorBus = ContextAwareHolder.loadContextAware().getBean(MonitorBus.class);
			if (ObjectUtil.isNotNull(monitorBus)) {
				nodeComponent.setMonitorBus(monitorBus);
			}
		}

		// 先取传进来的name值(配置文件中配置的)，再看有没有配置@LiteflowComponent标注
		// @LiteflowComponent标注只在spring体系下生效，这里用了spi机制取到相应环境下的实现类
		nodeComponent.setName(name);
		if (!type.isScript() && StrUtil.isBlank(nodeComponent.getName())) {
			nodeComponent
				.setName(LiteflowComponentSupportHolder.loadLiteflowComponentSupport().getCmpName(nodeComponent));
		}

		// 先从组件上取@RetryCount标注，如果没有，则看全局配置，全局配置如果不配置的话，默认是0
		// 默认retryForExceptions为Exception.class
		LiteflowRetry liteFlowRetryAnnotation = AnnoUtil.getAnnotation(nodeComponent.getClass(), LiteflowRetry.class);
		LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
		if (liteFlowRetryAnnotation != null) {
			nodeComponent.setRetryCount(liteFlowRetryAnnotation.retry());
			nodeComponent.setRetryForExceptions(liteFlowRetryAnnotation.forExceptions());
		}
		else {
			nodeComponent.setRetryCount(liteflowConfig.getRetryCount());
		}
		nodeComponent.setNodeExecutorClass(buildNodeExecutorClass(liteflowConfig));

		return nodeComponent;
	}

	private Class<? extends NodeExecutor> buildNodeExecutorClass(LiteflowConfig liteflowConfig) {
		Class<?> nodeExecutorClass;
		try {
			nodeExecutorClass = Class.forName(liteflowConfig.getNodeExecutorClass());
		}
		catch (ClassNotFoundException e) {
			throw new RuntimeException(e.getMessage());
		}
		return (Class<? extends NodeExecutor>) nodeExecutorClass;
	}

}
